use crate::controller::wireguard_endpoint::WireguardEndpointController;
use crate::error::Error;
use std::sync::Arc;
use wanmesh_server::dto::core::endpoint::EndpointType;
use wanmesh_server::dto::event::endpoint;

#[async_trait::async_trait]
pub trait SyncEndpoint<'a, T>: Send + Sync
where
    T: 'a + Send + Sync,
{
    async fn sync(&'a self, params: T) -> Result<(), Error>;
}

#[async_trait::async_trait]
pub trait DeleteEndpoint<'a, T>: Send + Sync
where
    T: 'a + Send + Sync,
{
    async fn delete(&'a self, params: T) -> Result<(), Error>;
}

pub struct EndpointController {
    node_id: String,
    api_client: Arc<wanmesh_server::http::client::Client>,
    wireguard_endpoint_controller: WireguardEndpointController,
}

impl EndpointController {
    pub fn new(node_id: String, api_client: Arc<wanmesh_server::http::client::Client>) -> Self {
        Self {
            node_id,
            api_client: api_client.clone(),
            wireguard_endpoint_controller: WireguardEndpointController::new(api_client),
        }
    }
    pub async fn sync_all(&self) -> Result<(), Error> {
        log::info!("开始同步所有endpoint，node_id={}", self.node_id);

        self.wireguard_endpoint_controller.sync_clean().await?;

        let mut offset = 0;
        let limit = 50;

        loop {
            let response_data = self
                .api_client
                .endpoint
                .list_info(&wanmesh_server::dto::endpoint::action::ListRequest {
                    offset,
                    limit,
                    filter: wanmesh_server::dto::core::endpoint::Filter {
                        node_id: Some(self.node_id.clone()),
                        endpoint_id: None,
                        endpoint_type: None,
                        name: None,
                    },
                })
                .await?;

            if response_data.list.len() == 0 {
                break;
            }
            self.sync(response_data.list.as_slice()).await?;
            if (response_data.list.len() as u64) < limit {
                break;
            }

            offset += limit;
        }

        Ok(())
    }
}

#[async_trait::async_trait]
impl<'a> SyncEndpoint<'a, &'a [wanmesh_server::dto::endpoint::EndpointInfo]>
    for EndpointController
{
    async fn sync(
        &'a self,
        endpoints: &'a [wanmesh_server::dto::endpoint::EndpointInfo],
    ) -> Result<(), Error> {
        for endpoint in endpoints {
            self.sync(endpoint).await?;
        }
        Ok(())
    }
}

#[async_trait::async_trait]
impl<'a> SyncEndpoint<'a, &'a wanmesh_server::dto::endpoint::EndpointInfo>
    for EndpointController
{
    async fn sync(
        &'a self,
        endpoint: &'a wanmesh_server::dto::endpoint::EndpointInfo,
    ) -> Result<(), Error> {
        match endpoint.inner.inner.endpoint_type {
            EndpointType::Srv6OverWireguard => {
                self.wireguard_endpoint_controller.sync(endpoint).await
            }
        }
    }
}

#[async_trait::async_trait]
impl<'a> SyncEndpoint<'a, &'a endpoint::SetupEventPayload> for EndpointController {
    async fn sync(&'a self, payload: &'a endpoint::SetupEventPayload) -> Result<(), Error> {
        let endpoint_config = self
            .api_client
            .endpoint
            .get_info(&wanmesh_server::dto::endpoint::GetRequest {
                endpoint_id: payload.endpoint_id.clone(),
            })
            .await?;
        self.sync(&endpoint_config).await
    }
}

#[async_trait::async_trait]
impl<'a> DeleteEndpoint<'a, &'a endpoint::DeleteEventPayload> for EndpointController {
    async fn delete(&'a self, event: &'a endpoint::DeleteEventPayload) -> Result<(), Error> {
        match event.endpoint_type {
            EndpointType::Srv6OverWireguard => self.wireguard_endpoint_controller.delete().await,
        }
    }
}
